package pa2.node;

import java.io.Serializable;
import java.rmi.RemoteException;
import java.util.Map;

import pa2.system.Peer;
import pa2.system.PeerImpl;
import pa2.util.Callback;
import pa2.util.EqualityCompare;
import pa2.util.Job;




public class LocalNode<K extends EqualityCompare<K>, V, M extends Map<K,V>> 
extends NodeDecorator<K,V,M> implements Node<K,V,M>, Serializable {

	private PeerImpl peer;

	protected LocalNode(Node<K,V,M> node, PeerImpl peer) throws RemoteException {
		super(node);
		this.peer = peer;		
	}


	@Override
	public void put(final K key, final V value, final Callback<K,V> callback) throws RemoteException {
		//System.out.println(this.peer.getName() + ": received get request for key " + key + " on node with key " + this.decoratedNode.getKey());
		this.peer.queue(new Job() {
			@Override
			public void run() {
				try {
//					System.out.println(
//							"Peer["+peer.getName()+"]: Node<"+LocalNode.this.decoratedNode.getKey()+
//							"> PUT "+value.toString()+" on "+Thread.currentThread().getName());
					synchronized(LocalNode.this.decoratedNode) {
						LocalNode.super.put(key, value, callback);
					}
				} catch (RemoteException e) {
					// TODO deregister peer @ SystemManager which didnt respond
					e.printStackTrace();
				}
			}
		});
	}

	@Override
	public void get(final K key, final Callback<K,V> callback) throws RemoteException {
		//System.out.println(this.peer.getName() + ": received get request for key " + key + " on node with key " + this.decoratedNode.getKey());		
		this.peer.queue(new Job() {
			@Override
			public void run() {
				try {
//					System.out.println(
//							"Peer["+peer.getName()+"]: Node<"+LocalNode.this.decoratedNode.getKey()+
//							"> GET "+key.toString()+" on "+Thread.currentThread().getName());
					synchronized(LocalNode.this.decoratedNode) {
						LocalNode.super.get(key, callback);
					}
				} catch (RemoteException e) {
					// TODO deregister peer @ SystemManager which didnt respond
					e.printStackTrace();
				}
			}
		});
	}

	@Override
	public void remove(final K key, final Callback<K,V> callback) throws RemoteException {
		this.peer.queue(new Job() {
			@Override
			public void run() {
				try {
//					System.out.println(
//							"Peer["+peer.getName()+"]: Node<"+LocalNode.this.decoratedNode.getKey()+
//							"> REMOVE "+key.toString()+" on "+Thread.currentThread().getName());
					synchronized(LocalNode.this.decoratedNode) {
						LocalNode.super.remove(key, callback);
					}
				} catch (RemoteException e) {
					// TODO deregister peer @ SystemManager which didnt respond
					e.printStackTrace();
				}
			}
		});
	}


	@Override
	public void addChild(Node<K, V, M> child) throws RemoteException {
		super.addChild(child);
//		System.out.println(
//				"Peer["+this.peer.getName()+"]: Node<"+LocalNode.this.decoratedNode.getKey()+
//				"> ADDED_CHILD on "+Thread.currentThread().getName());
	}


	@Override
	public void removeChild(Node<K, V, M> child) throws RemoteException {
		super.removeChild(child);
//		System.out.println(
//				"Peer["+this.peer.getName()+"]: Node<"+LocalNode.this.decoratedNode.getKey()+
//				"> REMOVED_CHILD on "+Thread.currentThread().getName());
	}

}
